package com.google.ad.ads

import android.app.Activity
import android.app.Application
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import com.google.ad.ads.databinding.AdUnifiedBinding
import com.google.ads.mediation.admob.AdMobAdapter
import com.google.android.gms.ads.AdError
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdLoader
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.AdView
import com.google.android.gms.ads.FullScreenContentCallback
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.MobileAds
import com.google.android.gms.ads.OnUserEarnedRewardListener
import com.google.android.gms.ads.VideoOptions
import com.google.android.gms.ads.interstitial.InterstitialAd
import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback
import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdOptions
import com.google.android.gms.ads.rewarded.RewardedAd
import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback
import java.lang.ref.WeakReference
import java.util.UUID

/**
 * @author Afra55
 * @date 2023/12/1
 * A smile is the best business card.
 * https://developers.google.com/admob/android/quick-start?hl=zh-cn
 * https://github.com/googleads/googleads-mobile-android-examples
 */
object GmsAds : LifecycleObserver, Application.ActivityLifecycleCallbacks {
    /* AD_UNIT_ID */
     var OPEN_AD_ID = ""
    private var BANNER_AD_ID = ""
    private var INTER_AD_ID = ""
    private var NATIVE_AD_ID = ""
    private var REWARD_AD_ID = ""

    private var hasInitOnce = false

    private var currentActivity: WeakReference<Activity?>? = null

    fun init(context: Application) {
        if (hasInitOnce) {
            return
        }
        hasInitOnce = true
        OPEN_AD_ID = context.getString(R.string.gms_ads_open)
        BANNER_AD_ID = context.getString(R.string.gms_ads_banner)
        INTER_AD_ID = context.getString(R.string.gms_ads_interstitial)
        NATIVE_AD_ID = context.getString(R.string.gms_ads_native)
        REWARD_AD_ID = context.getString(R.string.gms_ads_reward)

        context.registerActivityLifecycleCallbacks(this)
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)

        appOpenAdManager = AppOpenAdManager()
        MobileAds.initialize(context) {

            loadInterAd(context)
        }

    }

    /* open ad */
    private var isColdStartOpen = true
    private var appOpenAdManager: AppOpenAdManager? = null

    fun showOpenAd(activity: Activity) {
        appOpenAdManager?.showAdIfAvailable(activity)
    }

    /** LifecycleObserver method that shows the app open ad when the app moves to foreground. */
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onMoveToForeground() {
        // Show the ad (if available) when the app moves to foreground.
        if (isColdStartOpen) {
            // cold start do not show open
        } else {
            currentActivity?.get()?.let { appOpenAdManager?.showAdIfAvailable(it) }
            isColdStartOpen = false
        }
    }

    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {

    }

    override fun onActivityStarted(activity: Activity) {

        try {
            currentActivity = WeakReference(activity)
        } catch (e: Exception) {

        }
    }

    override fun onActivityResumed(activity: Activity) {

    }

    override fun onActivityPaused(activity: Activity) {

    }

    override fun onActivityStopped(activity: Activity) {

    }

    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {

    }

    override fun onActivityDestroyed(activity: Activity) {

    }

    /* BANNER AD*/
    fun getBannerAdView(context: Context, collapsible: Boolean = true): AdView {
        val adView = AdView(context)

        adView.setAdSize(AdSize.BANNER) // 高 50.dp
        adView.adUnitId = BANNER_AD_ID

        val extras = Bundle()
        if (collapsible) {
            extras.putString("collapsible", "bottom")
            extras.putString("collapsible_request_id", UUID.randomUUID().toString())
        }

        val adRequest = AdRequest.Builder()
            .addNetworkExtrasBundle(AdMobAdapter::class.java, extras)
            .build()


        adView.loadAd(adRequest)
        return adView
    }

    /* INTER AD */
    private var interstitialAd: InterstitialAd? = null
    private var interAdIsLoading: Boolean = false
    private var lastInterAdLoadedTime = 0L
    fun showInterAd(activity: Activity) {
        if (interstitialAd == null || System.currentTimeMillis() - lastInterAdLoadedTime > 3600000) {
            loadInterAd(activity.applicationContext)
            return
        }

        interstitialAd?.fullScreenContentCallback = object : FullScreenContentCallback() {
            override fun onAdDismissedFullScreenContent() {
                // Don't forget to set the ad reference to null so you
                // don't show the ad a second time.
                interstitialAd = null
                loadInterAd(activity.applicationContext)
            }

            override fun onAdFailedToShowFullScreenContent(adError: AdError) {
                // Don't forget to set the ad reference to null so you
                // don't show the ad a second time.
                interstitialAd = null
            }

            override fun onAdShowedFullScreenContent() {
                // Called when ad is dismissed.
            }

        }
        interstitialAd?.show(activity)
    }

    private fun loadInterAd(context: Context) {
        // Request a new ad if one isn't already loaded.
        if (interAdIsLoading || (interstitialAd != null && System.currentTimeMillis() - lastInterAdLoadedTime <= 3600000)) {
            return
        }
        interAdIsLoading = true

        val adRequest = AdRequest.Builder().build()

        InterstitialAd.load(
            context,
            INTER_AD_ID,
            adRequest,
            object : InterstitialAdLoadCallback() {
                override fun onAdFailedToLoad(adError: LoadAdError) {
                    interstitialAd = null
                    interAdIsLoading = false
                    val error =
                        "domain: ${adError.domain}, code: ${adError.code}, " + "message: ${adError.message}"

                }

                override fun onAdLoaded(ad: InterstitialAd) {
                    interstitialAd = ad
                    interAdIsLoading = false
                    lastInterAdLoadedTime = System.currentTimeMillis()
                }
            }
        )
    }

    /* NATIVE AD */
    fun getNativeAdView(context: Context, adFrame: FrameLayout) {
        val builder = AdLoader.Builder(context, NATIVE_AD_ID)
        builder.forNativeAd { nativeAd ->
            // OnUnifiedNativeAdLoadedListener implementation.
            // If this callback occurs after the activity is destroyed, you must call
            // destroy and return or you may get a memory leak.
            var activityDestroyed = false
            if (context is Activity) {
                activityDestroyed = context.isDestroyed
                if (activityDestroyed || context.isFinishing || context.isChangingConfigurations) {
                    nativeAd.destroy()
                    return@forNativeAd
                }
            }
            // You must call destroy on old ads when you are done with them,
            // otherwise you will have a memory leak.
            val unifiedAdBinding = AdUnifiedBinding.inflate(LayoutInflater.from(context))
            populateNativeAdView(nativeAd, unifiedAdBinding)
            adFrame.removeAllViews()
            adFrame.addView(unifiedAdBinding.root)
        }

        val videoOptions =
            VideoOptions.Builder().setStartMuted(true).build()

        val adOptions = NativeAdOptions.Builder().setVideoOptions(videoOptions).build()

        builder.withNativeAdOptions(adOptions)

        val adLoader =
            builder
                .withAdListener(
                    object : AdListener() {
                        override fun onAdFailedToLoad(loadAdError: LoadAdError) {
                            val error =
                                """
           domain: ${loadAdError.domain}, code: ${loadAdError.code}, message: ${loadAdError.message}
          """"

                        }
                    }
                )
                .build()

        adLoader.loadAd(AdRequest.Builder().build())
    }

    /**
     * Populates a [NativeAdView] object with data from a given [NativeAd].
     *
     * @param nativeAd the object containing the ad's assets
     * @param unifiedAdBinding the binding object of the layout that has NativeAdView as the root view
     */
    private fun populateNativeAdView(nativeAd: NativeAd, unifiedAdBinding: AdUnifiedBinding) {
        val nativeAdView = unifiedAdBinding.root

        // Set the media view.
        nativeAdView.mediaView = unifiedAdBinding.adMedia

        // Set other ad assets.
        nativeAdView.headlineView = unifiedAdBinding.adHeadline
        nativeAdView.bodyView = unifiedAdBinding.adBody
        nativeAdView.callToActionView = unifiedAdBinding.adCallToAction
        nativeAdView.iconView = unifiedAdBinding.adAppIcon
        nativeAdView.priceView = unifiedAdBinding.adPrice
        nativeAdView.starRatingView = unifiedAdBinding.adStars
        nativeAdView.storeView = unifiedAdBinding.adStore
        nativeAdView.advertiserView = unifiedAdBinding.adAdvertiser

        // The headline and media content are guaranteed to be in every UnifiedNativeAd.
        unifiedAdBinding.adHeadline.text = nativeAd.headline
        nativeAd.mediaContent?.let { unifiedAdBinding.adMedia.mediaContent = it }

        // These assets aren't guaranteed to be in every UnifiedNativeAd, so it's important to
        // check before trying to display them.
        if (nativeAd.body == null) {
            unifiedAdBinding.adBody.visibility = View.INVISIBLE
        } else {
            unifiedAdBinding.adBody.visibility = View.VISIBLE
            unifiedAdBinding.adBody.text = nativeAd.body
        }

        if (nativeAd.callToAction == null) {
            unifiedAdBinding.adCallToAction.visibility = View.INVISIBLE
        } else {
            unifiedAdBinding.adCallToAction.visibility = View.VISIBLE
            unifiedAdBinding.adCallToAction.text = nativeAd.callToAction
        }

        if (nativeAd.icon == null) {
            unifiedAdBinding.adAppIcon.visibility = View.GONE
        } else {
            unifiedAdBinding.adAppIcon.setImageDrawable(nativeAd.icon?.drawable)
            unifiedAdBinding.adAppIcon.visibility = View.VISIBLE
        }

        if (nativeAd.price == null) {
            unifiedAdBinding.adPrice.visibility = View.INVISIBLE
        } else {
            unifiedAdBinding.adPrice.visibility = View.VISIBLE
            unifiedAdBinding.adPrice.text = nativeAd.price
        }

        if (nativeAd.store == null) {
            unifiedAdBinding.adStore.visibility = View.INVISIBLE
        } else {
            unifiedAdBinding.adStore.visibility = View.VISIBLE
            unifiedAdBinding.adStore.text = nativeAd.store
        }

        if (nativeAd.starRating == null) {
            unifiedAdBinding.adStars.visibility = View.INVISIBLE
        } else {
            unifiedAdBinding.adStars.rating = nativeAd.starRating!!.toFloat()
            unifiedAdBinding.adStars.visibility = View.VISIBLE
        }

        if (nativeAd.advertiser == null) {
            unifiedAdBinding.adAdvertiser.visibility = View.INVISIBLE
        } else {
            unifiedAdBinding.adAdvertiser.text = nativeAd.advertiser
            unifiedAdBinding.adAdvertiser.visibility = View.VISIBLE
        }

        // This method tells the Google Mobile Ads SDK that you have finished populating your
        // native ad view with this native ad.
        nativeAdView.setNativeAd(nativeAd)

        // Get the video controller for the ad. One will always be provided, even if the ad doesn't
        // have a video asset.
//        val mediaContent = nativeAd.mediaContent
//        val vc = mediaContent?.videoController
//
//        // Updates the UI to say whether or not this ad has a video asset.
//        if (vc != null && mediaContent.hasVideoContent()) {
//            // Create a new VideoLifecycleCallbacks object and pass it to the VideoController. The
//            // VideoController will call methods on this object when events occur in the video
//            // lifecycle.
//            vc.videoLifecycleCallbacks =
//                object : VideoController.VideoLifecycleCallbacks() {
//                    override fun onVideoEnd() {
//                        // Publishers should allow native ads to complete video playback before
//                        // refreshing or replacing them with another ad in the same UI location.
//                        mainActivityBinding.refreshButton.isEnabled = true
//                        mainActivityBinding.videostatusText.text = "Video status: Video playback has ended."
//                        super.onVideoEnd()
//                    }
//                }
//        } else {
//            mainActivityBinding.videostatusText.text = "Video status: Ad does not contain a video asset."
//            mainActivityBinding.refreshButton.isEnabled = true
//        }
    }


    /* REWARD AD NO CACHE*/
    private var isLoading = false
    private var rewardedAd: RewardedAd? = null
    private var lastRewardedAdLoadTime = 0L
    var OnRewardedAdLoadListener: OnRewardedAdLoadListener? = null
    var OnRewardedAdShowListener:OnRewardedAdShowListener? = null

    fun hasRewarded():Boolean {
        if (rewardedAd != null && System.currentTimeMillis() - lastRewardedAdLoadTime <= 3600000) {
            return true
        }
        return false
    }

    fun loadRewardedAd(context: Context) {
        if (isLoading) {
            return
        }
        if (rewardedAd == null || System.currentTimeMillis() - lastRewardedAdLoadTime > 3600000) {
            isLoading = true
            var adRequest = AdRequest.Builder().build()

            RewardedAd.load(
                context.applicationContext,
                REWARD_AD_ID,
                adRequest,
                object : RewardedAdLoadCallback() {
                    override fun onAdFailedToLoad(adError: LoadAdError) {
                        isLoading = false
                        rewardedAd = null
                        OnRewardedAdLoadListener?.onAdFailedToLoad()
                        OnRewardedAdLoadListener = null
                    }

                    override fun onAdLoaded(ad: RewardedAd) {
                        lastRewardedAdLoadTime = System.currentTimeMillis()
                        rewardedAd = ad
                        isLoading = false
                        OnRewardedAdLoadListener?.onAdLoaded()
                        OnRewardedAdLoadListener = null
                    }
                }
            )
        }
    }

    fun showRewardedVideo(activity: Activity) {
        if (rewardedAd != null) {
            rewardedAd?.fullScreenContentCallback =
                object : FullScreenContentCallback() {
                    override fun onAdDismissedFullScreenContent() {
                        // Don't forget to set the ad reference to null so you
                        // don't show the ad a second time.
                        rewardedAd = null
//                        loadRewardedAd(activity)
                        OnRewardedAdShowListener?.onAdDismissedFullScreenContent();
                        OnRewardedAdShowListener = null
                    }

                    override fun onAdFailedToShowFullScreenContent(adError: AdError) {
                        // Don't forget to set the ad reference to null so you
                        // don't show the ad a second time.
                        rewardedAd = null
                        OnRewardedAdShowListener?.onAdFailedToShowFullScreenContent()
                        OnRewardedAdShowListener = null
                    }

                    override fun onAdShowedFullScreenContent() {
                        // Called when ad is dismissed.
                        OnRewardedAdShowListener?.onAdShowedFullScreenContent()
                    }
                }

            rewardedAd?.show(
                activity,
                OnUserEarnedRewardListener { rewardItem ->
                    // Handle the reward.
                    val rewardAmount = rewardItem.amount
                    val rewardType = rewardItem.type
//                    Log.d("TAG", "User earned the reward.")
                    OnRewardedAdShowListener?.OnUserEarnedRewardListener()
                }
            )
        }
    }
}